home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
Aminet 40
/
Aminet 40 (2000)(Schatztruhe)[!][Dec 2000].iso
/
Aminet
/
comm
/
tcp
/
Amster.lha
/
Amster_Install
/
Source
/
download.c
< prev
next >
Wrap
C/C++ Source or Header
|
2000-07-31
|
21KB
|
847 lines
/*
** Download
*/
#include "include/config.h"
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <proto/exec.h>
#include <proto/socket.h>
#include <proto/dos.h>
#include <proto/asl.h>
#include <exec/memory.h>
#include <libraries/dos.h>
#include <libraries/asl.h>
#include <netdb.h>
#include <sys/time.h>
#include <sys/socket.h>
#include <sys/ioctl.h>
#include <netinet/tcp.h>
#include <bsdsocket/socketbasetags.h>
#include <error.h>
#include <time.h>
#include "include/mui.h"
#include <MUI/NListview_mcc.h>
#include <MUI/NFloattext_mcc.h>
#include "include/gui.h"
#include "include/rexx.h"
#include "include/panel.h"
#include "include/transfer.h"
#include "include/download.h"
#include "include/prefs.h"
#include "include/share.h"
#include "md5.h"
#include "amster_Cat.h"
#include "include/protos.h"
int dl_count = 0;
int QueueCount = 0;
int WaitingCount = 0;
/* Private functions */
ULONG dl_new(struct IClass *cl, Object *obj, struct opSet *msg);
void dl_startq(struct TransferData *data, Object *obj, char *title, char *user, u_long ip, int port);
void dl_checkqueue(struct TransferData *data);
void DownloadRetry(struct TransferData *data, Object *obj, char *title, char *user, int limit);
void PollWaiting(struct TransferData *data, Object *obj);
int dl_filename(songtrans sd);
char *chkmd5_fromlock(BPTR lock);
int dl_askfname(char *fname);
void dl_handlemsg(thread t, int com, APTR data);
void dl_resume(struct TransferData *data);
void dl_cps(struct TransferData *data);
__asm __saveds void dl_sucker(void);
MUIF dl_dispatch(REG(a0) struct IClass *cl,REG(a2) Object *obj,REG(a1) Msg msg)
{
struct TransferData *data;
switch(msg->MethodID) {
case OM_NEW:
return(dl_new(cl, obj, (APTR)msg));
case MUIM_Window_Setup:
return(dl_setup(cl, obj, (APTR)msg));
case MUIM_Window_Cleanup:
return(dl_muicleanup(cl, obj, (APTR)msg));
case DL_ADD:
data = INST_DATA(cl, obj);
DoMethod(data->list, MUIM_NList_InsertSingle, (songtrans)(((muimsg)msg)->arg1), MUIV_NList_Insert_Bottom);
return(NULL);
case DL_START:
data = INST_DATA(cl, obj);
dl_startq(data, obj, (char *)(((muimsg)msg)->arg1), (char *)(((muimsg)msg)->arg2), (u_long)(((muimsg)msg)->arg3), (int)(((muimsg)msg)->arg4));
return(NULL);
case DL_UPDATE:
{
long pos = MUIV_NList_GetPos_Start;
data = INST_DATA(cl, obj);
DoMethod(data->list, MUIM_NList_GetPos, (((muimsg)msg)->arg1), &pos);
DoMethod(data->list, MUIM_NList_Redraw, pos);
return(NULL);
}
case DL_CPS:
data = INST_DATA(cl, obj);
dl_cps(data);
return(NULL);
case DL_CLEANUP:
data = INST_DATA(cl, obj);
TransferCleanup(data);
return(NULL);
case DL_CLEANUP_SINGLE:
data = INST_DATA(cl, obj);
TransferCleanupSingle(data, (songtrans)(((muimsg)msg)->arg1));
return NULL;
case DL_ABORT:
data = INST_DATA(cl, obj);
TransferAbort(data);
return(NULL);
case DL_RESUME:
data = INST_DATA(cl, obj);
dl_resume(data);
return(NULL);
case DL_INFO:
data = INST_DATA(cl, obj);
TransferInfo(data);
return(NULL);
case DL_PLAY:
{
songtrans st;
data = INST_DATA(cl, obj);
DoMethod(data->list, MUIM_NList_GetEntry, MUIV_NList_GetEntry_Active, &st);
if (!st) return(NULL);
if (st->state < DLS_DOWN || !(st->fname)) return(NULL);
prf_event(PRFE_PLAYMP3, st->fname);
return(NULL);
}
case DL_SETERROR:
data = INST_DATA(cl, obj);
TransferSetError(data, (char *)(((muimsg)msg)->arg1), (char *)(((muimsg)msg)->arg2), (int)(((muimsg)msg)->arg3));
return(NULL);
case DL_RETRY:
data = INST_DATA(cl, obj);
DownloadRetry(data, obj, (char *)(((muimsg)msg)->arg1), (char *)(((muimsg)msg)->arg2), (int)(((muimsg)msg)->arg3));
return(NULL);
case DL_POLLWAIT:
data = INST_DATA(cl, obj);
PollWaiting(data, obj);
return(NULL);
case DL_REMWAITING:
data = INST_DATA(cl, obj);
if (((songtrans)(((muimsg)msg)->arg1))->state == DLS_WAIT) {
if (--WaitingCount == 0) DoMethod(_app(obj), MUIM_Application_RemInputHandler, &data->waitnode);
/* This was the last waiting entry - remove input handler */
}
return(NULL);
case DL_SETDELAY:
data = INST_DATA(cl, obj);
data->waitnode.ihn_Millis = (int)(((muimsg)msg)->arg1)*1000;
return(NULL);
case DL_WATCHER:
data = INST_DATA(cl, obj);
TransferWatcher(data);
return(NULL);
case DL_COUNTDECREMENT:
data = INST_DATA(cl, obj);
if (--dl_count == 0) DoMethod(_app(obj), MUIM_Application_RemInputHandler, &data->watchnode);
dl_checkqueue(data);
return(NULL);
case DL_COUNTINCREMENT:
data = INST_DATA(cl, obj);
if (dl_count++ == 0) DoMethod(_app(obj), MUIM_Application_AddInputHandler, &data->watchnode);
return(NULL);
case DL_CHECKQUEUE:
data = INST_DATA(cl, obj);
dl_checkqueue(data);
return(NULL);
}
return(DoSuperMethodA(cl, obj, msg));
}
ULONG dl_new(struct IClass *cl, Object *obj, struct opSet *msg)
{
static struct Hook downlistdispHook = { {0,0}, &translistdisp, NULL, NULL };
struct TransferData *data;
Object *list, *info, *playbut, *abortbut, *resbut, *cleanbut;
if (obj = (Object *)DoSuperNew(cl, obj,
MUIA_HelpNode, "download",
MUIA_Window_Title, MSG_DL_TITLE,
MUIA_Window_ID, MAKE_ID('D','O','W','N'),
WindowContents, VGroup,
Child, list = NListviewObject,
MUIA_NListview_NList, NListObject,
InputListFrame,
MUIA_Font, MUIV_Font_Tiny,
MUIA_NList_Title, TRUE,
MUIA_NList_Format, "BAR, BAR, BAR, BAR, BAR",
MUIA_NList_DisplayHook, &downlistdispHook,
MUIA_NList_DragSortable, TRUE,
MUIA_CycleChain, 1,
End,
End,
Child, info = TextObject,
TextFrame,
MUIA_Background, MUII_TextBack,
MUIA_Text_PreParse, "\33c",
End,
Child, HGroup,
Child, HGroup,
Child, playbut = SimpleButton(MSG_DL_PLAY_GAD),
MUIA_ShortHelp, MSG_PLAY_HELP,
End,
Child, HSpace(4),
Child, HGroup,
Child, abortbut = SimpleButton(MSG_DL_ABORT_GAD),
MUIA_ShortHelp, MSG_ABORT_HELP,
End,
Child, HGroup,
Child, resbut = SimpleButton(MSG_DL_RESUME_GAD),
MUIA_ShortHelp, MSG_RESUME_HELP,
End,
Child, HSpace(4),
Child, HGroup,
Child, cleanbut = SimpleButton(MSG_DL_CLEANUP_GAD),
MUIA_ShortHelp, MSG_CLEANUP_HELP,
End,
End,
End,
TAG_MORE, msg->ops_AttrList))
{
data = INST_DATA(cl,obj);
data->list = list;
data->info = info;
data->ihnode.ihn_Object = obj;
data->ihnode.ihn_Millis = 1000;
data->ihnode.ihn_Method = DL_CPS;
data->ihnode.ihn_Flags = MUIIHNF_TIMER;
data->waitnode.ihn_Object = obj;
data->waitnode.ihn_Millis = prf->QueueDelay*1000; /* Poll interval in milliseconds */
data->waitnode.ihn_Method = DL_POLLWAIT;
data->waitnode.ihn_Flags = MUIIHNF_TIMER;
data->watchnode.ihn_Object = obj;
data->watchnode.ihn_Millis = 10000;
data->watchnode.ihn_Method = DL_WATCHER;
data->watchnode.ihn_Flags = MUIIHNF_TIMER;
DoMethod(playbut, MUIM_Notify, MUIA_Pressed, FALSE, obj, 1, DL_PLAY );
DoMethod(resbut, MUIM_Notify, MUIA_Pressed, FALSE, obj, 1, DL_RESUME );
DoMethod(abortbut, MUIM_Notify, MUIA_Pressed, FALSE, obj, 1, DL_ABORT );
DoMethod(cleanbut, MUIM_Notify, MUIA_Pressed, FALSE, obj, 1, DL_CLEANUP);
DoMethod(list, MUIM_Notify, MUIA_NList_EntryClick, MUIV_EveryTime, obj, 1, DL_INFO);
DoMethod(obj, MUIM_Notify, MUIA_Window_CloseRequest, TRUE, gui->iconpanel, 1, PANEL_CLOSEDL);
return((ULONG)obj);
}
return(0);
}
void dl_addq(song s)
/* This is the initial function, called from resultview.c */
{
songtrans sd;
sd = malloc(sizeof(_songtrans));
if (!sd) return;
memset(sd, 0, sizeof(_songtrans));
sd->song = nap_songdup(s);
if (!sd->song) {
free(sd);
return;
}
sd->size = s->size;
sd->mynick = prf->user;
sd->type = TYPE_DOWNLOAD_OUT;
sd->reqtime = time(NULL);
if (dl_count >= prf->DownloadQueueLimit && prf->DownloadQueueLimit < 26) {
sd->state = DLS_QUEUE;
QueueCount++;
}
else {
sprintf(nap_buf, "\"%s\" \"%s\"", s->user, s->title);
nap_send(NAPC_FILEINFOREQ);
sd->state = DLS_PREP;
DoMethod(gui->dwin, DL_COUNTINCREMENT);
}
DoMethod(gui->dwin, DL_ADD, sd);
}
void dl_startq(struct TransferData *data, Object *obj, char *title, char *user, u_long ip, int port)
/* This is the initial function, when the actual download is about to
take place (acknowledged by server) - called from napster.c (via DL_START) */
{
u_long tmp;
songtrans sd;
long i;
for (i=0; ; i++) {
DoMethod(data->list, MUIM_NList_GetEntry, i, &tmp);
if (!tmp) return;
sd = (songtrans)tmp;
if ((sd->state == DLS_PREP || sd->state == DLS_WAIT || sd->state == DLS_QUEUE) && stricmp(user,sd->song->user)==0 && strcmp(title,sd->song->title)==0) break;
}
if (sd->t) return; /* Already in a thread */
if (!dl_filename(sd)) {
if (sd->state == DLS_WAIT) DoMethod(gui->dwin, DL_REMWAITING, sd);
else if (sd->state == DLS_QUEUE) QueueCount--;
else {
sd->state = DLS_ABORT;
DoMethod(gui->dwin, DL_COUNTDECREMENT);
}
sd->state = DLS_ABORT;
DoMethod(gui->dwin, DL_UPDATE, sd);
return;
}
sd->song->ip = ip; /* In case of browse result, the IP isn't already there */
sd->ip = ip;
sd->port = port;
sd->s = -1;
sd->oldsize = sd->cur;
if (sd->state == DLS_WAIT) DoMethod(gui->dwin, DL_REMWAITING, sd);
if (sd->state == DLS_QUEUE) {
QueueCount--;
DoMethod(gui->dwin, DL_COUNTINCREMENT);
}
else if (sd->state == DLS_WAIT) {
DoMethod(gui->dwin, DL_COUNTINCREMENT);
}
sd->state = DLS_PREP;
sd->t = th_spawn(dl_handlemsg, "Amster downloader", dl_sucker, prf->DownloadTaskPri, sd);
if (!sd->t) {
sd->state = DLS_ERROR;
DoMethod(gui->dwin, DL_UPDATE, sd);
}
}
void dl_checkqueue(struct TransferData *data)
{
u_long tmp;
songtrans sd;
long i;
if (dl_count >= prf->DownloadQueueLimit && prf->DownloadQueueLimit < 26) return;
for (i=0; ; i++) {
DoMethod(data->list, MUIM_NList_GetEntry, i, &tmp);
if (!tmp) return;
sd = (songtrans)tmp;
if (sd->state == DLS_QUEUE) break;
}
sd->reqtime = time(NULL); /* Reset time to avoid watcher timeouts */
sprintf(nap_buf, "\"%s\" \"%s\"", sd->song->user, sd->song->title);
nap_send(NAPC_FILEINFOREQ);
DoMethod(gui->dwin, DL_COUNTINCREMENT);
sd->state = DLS_PREP;
QueueCount--;
DoMethod(gui->dwin, DL_UPDATE, sd);
}
void DownloadRetry(struct TransferData *data, Object *obj, char *title, char *user, int limit)
/* Called from napster.c when a file cannot be downloaded yet (busy) */
{
u_long tmp;
songtrans sd;
long i;
for (i=0; ; i++) {
DoMethod(data->list, MUIM_NList_GetEntry, i, &tmp);
if (!tmp) return;
sd = (songtrans)tmp;
if (sd->state == DLS_PREP && strcmp(sd->song->title, title) == 0 && stricmp(sd->song->user, user) == 0) break;
}
if (sd->RetryCount >= prf->QueueRetries) return; /* We've already given up */
else if (limit == 0) {
sd->state = DLS_ERROR;
sd->error = ERROR_TEASER; /* Queue limit is 0 = file can't be downloaded by anyone */
DoMethod(gui->dwin, DL_COUNTDECREMENT);
}
else {
sd->state = DLS_WAIT;
sd->ErrorCode = limit;
WaitingCount++;
if (WaitingCount == 1) DoMethod(_app(obj), MUIM_Application_AddInputHandler, &data->waitnode);
/* This is the first waiting entry - add input handler */
DoMethod(gui->dwin, DL_COUNTDECREMENT);
/* We consider this queued and let other downloads start */
}
DoMethod(gui->dwin, DL_UPDATE, sd);
}
void PollWaiting(struct TransferData *data, Object *obj)
{
u_long tmp;
songtrans sd;
long i;
if (WaitingCount == 0) return; /* Don't waste time! */
for (i=0; ; i++) {
DoMethod(data->list, MUIM_NList_GetEntry, i, &tmp);
if (!tmp) return;
sd = (songtrans)tmp;
if (sd->state == DLS_WAIT && QueueCount == 0) {
if (sd->RetryCount < prf->QueueRetries) {
sprintf(nap_buf,"\"%s\" \"%s\"", sd->song->user, sd->song->title);
nap_send(NAPC_FILEINFOREQ);
sd->RetryCount++;
}
else { /* We give up! */
sd->state = DLS_ERROR;
sd->error = ERROR_BUSY;
DoMethod(gui->dwin, DL_REMWAITING, sd);
DoMethod(gui->dwin, DL_UPDATE, sd);
}
}
}
}
void dl_resume(struct TransferData *data)
{
u_long item;
songtrans sd;
DoMethod(data->list, MUIM_NList_GetEntry, MUIV_NList_GetEntry_Active, &item);
if (!item) return;
sd = (songtrans)item;
if (sd->state < DLS_ABORT) return; /* Can't resume files that's already in progress */
if (sd->t) return;
if (dl_count >= prf->DownloadQueueLimit && prf->DownloadQueueLimit < 26) {
sd->state = DLS_QUEUE;
QueueCount++;
}
else {
sd->reqtime = time(NULL);
sprintf(nap_buf, "\"%s\" \"%s\"", sd->song->user, sd->song->title);
nap_send(NAPC_FILEINFOREQ);
sd->state = DLS_PREP;
DoMethod(gui->dwin, DL_COUNTINCREMENT);
}
DoMethod(gui->dwin, DL_UPDATE, sd);
}
int dl_filename(songtrans sd)
{
BPTR lock;
__aligned struct FileInfoBlock fib;
char md5[80] = "";
char *fname, temp[108];
long oldsize=0;
int way, reqrc;
char *expl, *choice;
fname = malloc(512);
if (!fname) return 0;
strcpy(fname, prf->dlpath);
strncpy(temp, nap_strippath(sd->song->title), 107);
AddPart(fname, temp, 511);
if (prf->askfile) {
if (!dl_askfname(fname)) return 0;
}
else { /* Needs optimization and elegance */
if (strlen(nap_strippath(sd->song->title)) > prf->NameLength) {
strcpy(fname+strlen(fname)-strlen(nap_strippath(sd->song->title))-4+prf->NameLength, fname+strlen(fname)-4);
}
}
lock = Lock(fname, ACCESS_READ);
if (!lock) {
sd->fname = fname;
sd->cur = 0;
return(1);
}
if (Examine(lock, &fib)) {
oldsize = fib.fib_Size;
sscanf(fib.fib_Comment, "md5: %[^;]", &md5);
if (md5[0] == 0 && oldsize >= 300032) strcpy(md5, chkmd5_fromlock(lock));
else UnLock(lock);
}
else UnLock(lock);
if (sd->size <= oldsize) {
way = 1;
expl = (char *)MSG_DL_RESBIGSIZE;
choice = (char *)MSG_DL_OVERCANCEL_GAD;
}
else if (md5[0] == 0) {
way = 0;
expl = (char *)MSG_DL_NOMD5INFO;
choice = (char *)MSG_DL_RESUMECANCEL_GAD;
}
else if (strcmp(md5,sd->song->md5)!=0) {
way = 1;
expl = (char *)MSG_DL_NOMATCH;
choice = (char *)MSG_DL_OVERCANCEL_GAD;
}
else {
way = 2;
expl = (char *)MSG_DL_RESMATCH;
choice = (char *)MSG_DL_RESUMEOVER_GAD;
}
reqrc = MUI_Request(gui->app, gui->win, 0L,
(char *)MSG_DL_RESUME_INFO,
choice,
(char *)MSG_DL_RESUME_MSG,
fname,
oldsize,
sd->size,
md5[0]==0 ? (char*)MSG_DL_NOMD5 : md5,
sd->song->md5,
expl);
if (reqrc == 0) return(0);
if ((way==0 || way==2) && reqrc == 1) {
sd->fname = fname;
sd->cur = oldsize;
return(1);
}
if (reqrc == 2) {
if (dl_askfname(fname)) {
sd->fname = fname;
sd->cur = 0;
return(1);
}
else return(0);
}
sd->cur = 0;
sd->fname = fname;
return(1);
}
char *chkmd5_fromlock(BPTR lock)
{
APTR buffer;
BPTR fh;
int len;
char md5[33] = "";
md5_state_t state;
md5_byte_t digest[16];
int di;
md5_init(&state);
if (fh = OpenFromLock(lock)) {
if (buffer = AllocMem(300032, MEMF_ANY)) {
len = Read(fh, buffer, 300032);
if (len > 0) {
md5_append(&state, (const md5_byte_t *)buffer, len);
md5_finish(&state, digest);
for (di = 0; di < 16; ++di)
sprintf(md5+di*2, "%02x", digest[di]);
}
FreeMem(buffer, 300032);
}
Close(fh);
}
else UnLock(lock);
return md5;
}
int dl_askfname(char *fname)
{
struct FileRequester *freq;
u_long win;
freq = AllocAslRequestTags(ASL_FileRequest, TAG_DONE);
if (!freq) return(0);
get(gui->dwin, MUIA_Window_Window, &win);
if (AslRequestTags(freq,
ASLFR_Window, win,
ASLFR_TitleText, MSG_DL_SELECTFILE,
ASLFR_InitialFile, nap_strippath(fname),
ASLFR_InitialDrawer, prf->dlpath,
ASLFR_DoSaveMode, TRUE,
TAG_DONE)) {
strcpy(fname, freq->fr_Drawer);
AddPart(fname, freq->fr_File, 511);
FreeAslRequest(freq);
return(1);
}
else {
FreeAslRequest(freq);
return(0);
}
}
void dl_handlemsg(thread t, int com, APTR data)
/* This is the function that receives messages from the download
thread. It's called when something needs to be done in the
main thread (i.e. updating the window). */
{
songtrans sd=(songtrans)t->data;
switch (com) {
case THC_STARTUP:
sd->ts = 1;
nap_sendbuf(NAPC_DLINC, "");
break;
case THC_EXIT:
sd->error = (int)data;
TransferHandleError(sd);
sd->ts = 0;
sd->t = NULL;
DoMethod(gui->dwin, DL_COUNTDECREMENT);
nap_sendbuf(NAPC_DLCOMPLETE, "");
if (sd->state == DLS_FIN && (prf->AutoCleanup == 1 || prf->AutoCleanup == 3)) {
DoMethod(gui->dwin, DL_CLEANUP_SINGLE, sd);
break;
}
break;
case DLC_STATE:
sd->state = (int)data;
case DLC_UPDATE:
DoMethod(gui->dwin, DL_UPDATE, sd);
break;
case DLC_ADDSHARE:
DoMethod(gui->shwin, SHARE_ADDFILE, sd->song, sd->fname);
break;
}
}
void dl_cps(struct TransferData *data)
{
songtrans sd;
u_long item;
int i;
for (i=0; ; i++) {
DoMethod(data->list, MUIM_NList_GetEntry, i, &item);
if (!item) return;
sd = (songtrans)item;
if (sd->state == DLS_DOWN) {
CalculateCps(sd);
DoMethod(gui->dwin, DL_UPDATE, sd);
}
}
}
/* thread code */
__asm __saveds void dl_sucker(void)
{
thread t;
songtrans sd;
struct Library *DosBase;
struct Library *SocketBase;
char *buffer;
long tmp;
long s;
thmsg m;
char cmnt[80];
int count;
t = thr_init();
if (!t) return;
sd = t->data;
if (!InitTransferThread(t, sd)) return;
sd->RetryCount = 0;
s = sd->s;
buffer = sd->buffer;
DosBase = sd->DosBase;
SocketBase = sd->SocketBase;
while (1) {
u_long sigs;
sigs = Wait(sd->nsigm | sd->msigm);
if (sigs&(sd->msigm)) {
m = (thmsg)GetMsg(t->port);
if (m) {
if (m->com == THC_EXIT) {
sd->state = DLS_ABORT;
thr_message(t, DLC_UPDATE, 0);
ExitTransferThread(sd, 0);
return;
}
if (!m->isreply) {
m->isreply=1;
ReplyMsg((struct Message *)m);
}
}
}
if (sigs&(sd->nsigm)) {
FD_ZERO(&sd->fds);
FD_SET(s,&sd->fds);
sd->tv.tv_sec = 0;
sd->tv.tv_usec = 0;
switch (sd->state) {
case DLS_CON:
if (WaitSelect(s+1,NULL,&sd->fds,NULL,&sd->tv,0) != 1) break;
{
sd->state = DLS_REQ;
tmp = 0;
IoctlSocket(s, FIONBIO, (char*)&tmp);
/* Disable non-blocking I/O to the socket */
}
case DLS_REQ:
if (WaitSelect(s+1,&sd->fds,NULL,NULL,&sd->tv,0) != 1) break;
{
tmp = recv(s, buffer, 1, 0);
if (tmp != 1) {
sd->ErrorCode = Errno();
ExitTransferThread(sd, ERROR_NET);
return;
}
if (buffer[0] != '1') {
ExitTransferThread(sd, 29);
return;
}
thr_message(t, DLC_UPDATE, 0);
send(s, "GET", 3, 0);
sprintf(buffer, "%s \"%s\" %d", sd->mynick, sd->song->title, sd->cur);
send(s, buffer, strlen(buffer), 0);
tmp = recv(s, buffer, 32, 0);
if (tmp < 1) {
sd->ErrorCode = Errno();
ExitTransferThread(sd, ERROR_NET);
return;
}
buffer[tmp] = '\0';
if (atoi(buffer) != sd->size) {
if (strcmp(buffer, "FILE NOT FOUND") == 0 || strcmp(buffer, "FILE NOT SHARED") == 0) {
ExitTransferThread(sd, ERROR_NOTFOUND);
return;
}
else if (strcmp(buffer, "INVALID REQUEST") == 0) {
ExitTransferThread(sd, ERROR_INVALIDREQUEST);
return;
}
ExitTransferThread(sd, 12);
return;
}
sd->f = Open(sd->fname, MODE_READWRITE);
if (!sd->f) {
sd->ErrorCode = IoErr();
ExitTransferThread(sd, ERROR_FILEOPEN);
return;
}
sprintf(cmnt, "md5:%s; size:%ld; user:%s", sd->song->md5, sd->size, sd->song->user);
SetComment(sd->fname, cmnt);
Seek(sd->f, sd->cur, OFFSET_BEGINNING);
sd->state = DLS_DOWN;
sd->starttime = time(NULL);
sd->resumestart = sd->cur;
thr_message(t, DLC_UPDATE, 0);
}
case DLS_DOWN:
if (WaitSelect(s+1,&sd->fds,NULL,NULL,&sd->tv,0) != 1) break;
while (sd->cur < sd->size) {
tmp = recv(s, buffer, 4096, 0);
if (tmp < 1) {
sd->ErrorCode = Errno();
ExitTransferThread(sd, ERROR_NET);
return;
}
SetIoErr(0L); /* FWrite doesn't clear IoErr() due to a bug */
count = FWrite(sd->f, buffer, 1, tmp);
sd->cur += count;
if (count != tmp) {
sd->ErrorCode = IoErr();
ExitTransferThread(sd, ERROR_FILEWRITE);
return;
}
m = (thmsg)GetMsg(t->port);
if (m) {
if (m->com == THC_EXIT) {
thr_message(t, DLC_STATE, (APTR)DLS_ABORT);
ExitTransferThread(sd, 0);
return;
}
if (!m->isreply) {
m->isreply = 1;
ReplyMsg((struct Message *)m);
}
}
FD_ZERO(&sd->fds);
FD_SET(s,&sd->fds);
}
sd->state = DLS_FIN;
thr_message(t, DLC_UPDATE, 0);
if ((strlen(sd->song->user)+strlen(sd->host)+9) < 80) sprintf(cmnt, "from %s (@%s)", sd->song->user, sd->host);
else sprintf(cmnt, "from %s (@%s)", sd->song->user, Inet_NtoA(sd->song->ip));
/* If the hostname is too long for the file comment, we fall back to the IP */
SetComment(sd->fname, cmnt);
if (prf->autoadd) thr_message(t, DLC_ADDSHARE, 0);
ExitTransferThread(sd, 0);
return;
}
}
}
ExitTransferThread(sd, 0);
}